//===========================================================================
// This file was modified as part of an ASP.NET 2.0 Web project conversion.
// The class name was changed and the class modified to inherit from the abstract base class 
// in file 'App_Code\Migrated\personnel\Stub_expiredfundallocation_aspx_cs.cs'.
// During runtime, this allows other classes in your web application to bind and access 
// the code-behind page using the abstract base class.
// The associated content page 'personnel\expiredfundallocation.aspx' was also modified to refer to the new class name.
// For more information on this code pattern, please refer to http://go.microsoft.com/fwlink/?LinkId=46995 
//===========================================================================

using System;
using System.Collections;
using System.Text;
using System.Web;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Context;
using PHSRAG.Insight21.Personnel;
using PHSRAG.Insight21.Policy;
using PHSRAG.Insight21.SearchContext;
using PHSRAG.Utility;
using PHSRAG.WebControls;
using FundAllocation = PHSRAG.Insight21.Personnel.ExpiredFundAllocation;
using PersonnelConstants = PHSRAG.Insight21.Personnel.Constants;

namespace PHSRAG.Insight21
{
    /// <summary>
    /// The ExpiredFundAllocation class supports the ExpiredFundAllocation.aspx page.
    /// It displays the all the expired fund allocation details the currently loggedin user has access to.
    /// </summary>
    /// <remarks>
    /// The ExpiredFundAllocation page supports searching/filtering the expired fund data
    /// based on user-defined and user-selectable search criteria.
    /// Following is the list of such criteria:
    /// <list type="bullet">
    /// <item><description>Employee Last Name (free-form entry)</description></item>
    /// <item><description>Employee First Name (free-form entry)</description></item>
    /// <item><description>Fund Number (free-form entry)</description></item>
    /// <item><description>Effective Salary Date From/To (select both from a calender)</description></item>
    /// <item><description>Fund Ending Date (select from a drop-down list)</description></item>
    /// </list>
    /// </remarks>
    public partial class ExpiredFundAllocation : NoCachePage
    {
        #region Constants

        private const string CurrentPageIndexKey = "CurrentPageIndex_F586B2CE-10A4-4BF7-A76A-61B0289B3FDC";
        private const string FeedIndicatorSymbol = "*";
        private const int FirstChildControlIndex = 0;

        #endregion

        #region Enumerations (Private)

        /// <summary>
        /// The DataGridColumns enumeration defines values 
        /// for indexing columns in the datagrid.
        /// </summary>
        private enum DataGridColumns
        {
            EmployeeJobMapId,
            FundNumber,
            ProjectEndDate,
            EmployeeName,
            AllocationStartDate,
            AllocationEndDate,
            SalaryAllocated,
            HRDepartment
        }

        #endregion

        #region Instance Variables (Private)

        private ICachePolicy cachePolicy;
        private ICachePolicy pageCachePolicy;

        #endregion

        #region Private Properties

        /// <summary>
        /// Get the expired fund allocation information the currently logged in user has access to.The list of
        /// expired fund allocations is maintained by the ExpiredFundAllocations instance within its data container
        /// This object is cached.
        /// </summary>
        private ExpiredFundAllocations FundAllocationsInstance
        {
            get
            {
                ExpiredFundAllocations expiredFundAlloc =
                    ResultsCache.GetObject(cachePolicy, ExpiredFundAllocations.CacheKey) as ExpiredFundAllocations;

                if (expiredFundAlloc == null)
                {
                    expiredFundAlloc = new ExpiredFundAllocations();
                    expiredFundAlloc.Load(DataAccess.GetConnectionString()
                        , ((UserContext) cachePolicy.GetCachedObject(UserContext.CacheKey)).DomainUserId);

                    ResultsCache.SetObject(cachePolicy, ExpiredFundAllocations.CacheKey, expiredFundAlloc);
                }

                pageCachePolicy.Cache(Keys.ExcelRecordCountKey, expiredFundAlloc.Count);
                return expiredFundAlloc;
            }
        }

        /// <summary>
        /// Get/Set the current page within the datagrid for display. This information persists across page loads.
        /// This information is cached using the page cache policy and the CurrentPageIndexKey
        /// Get: Return the value from the page cache policy, returns 0 if its not present in cache
        /// Set: Set the value and update the cache
        /// </summary>
        private int CurrentPageIndex
        {
            get
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.ExpiredFundAllocationPageKey) as Hashtable;
                return (h == null || h[CurrentPageIndexKey] == null) ? 0 : (int) h[CurrentPageIndexKey];
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.ExpiredFundAllocationPageKey) as Hashtable ?? new Hashtable();
                h[CurrentPageIndexKey] = value;
                expiredFundGrid.CurrentPageIndex = value;
                pageCachePolicy.Cache(Keys.ExpiredFundAllocationPageKey, h);
            }
        }

        #endregion

        #region Constructors

        #endregion

        #region Event Handlers

        #region Page load

        /// <summary>
        /// Handler for the event raised when the page is being loaded.
        /// Initialize the bread crumb control, set the page size for the data grid, and load the data grid with data.
        /// If on the first page within the data grid, initalize the pager control.
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            annunciator.Message = string.Empty;
            annunciator.Title = string.Empty;

            breadCrumb.Add("Expired Fund Report"
                , Settings.GetKeyValue
                    ("SubNavigation.Personnel.ExpiredFundReportURL", string.Empty)
                , Constants.DefaultSummaryPageRank);
            reportDownload.SQLReportName = SSRSRequest.ReportNames.Personnel.ExpiredFundAllocation; //"Personnel_ExpiredFundAllocation"
            if (IsPostBack)
            {
                ManagePagination();
            }
            else
            {
                ResultsCache.PurgeObject(cachePolicy);

                ((ExpansionToggler) expandingPanel.FindControl("expansionToggler")).HelpText =
                    InsightUtilities.Constants.SearchHelpText;

                expiredFundGrid.PageSize = Settings.GetKeyValue(Constants.DataGridPageSizeKey
                    , Constants.DefaultDatagridPageSize);
                ProcessSearch();

                CommonSearchContext searchContext = (CommonSearchContext) cachePolicy.GetCachedObject(CommonSearchContext.CacheKey);
                SearchCriteria searchCriteria = searchContext.GetSearchCriteria(Page.Request.Url.ToString());
                hiddenSearchCriteria.Value = HttpUtility.UrlEncode(AddRefreshDatesToCriteria(searchCriteria));
            }
        }

        #endregion

        #region Datagrid event handlers

        /// <summary>
        /// Handler for event raised while each data grid item is created.
        /// Help in putting the symbol denoting the sort column in the data grid.
        /// If the item being created is the data grid header:
        /// <list type="bullet">
        /// <item><description>Get the sort column and sort order from the ExpiredFundAllocations instance in the cache</description></item>
        /// <item><description>Create a Hashtable of column indeces, keyed by the sort expression of each column</description></item>
        /// <item><description>Using the hash table add a label to the column on which sort has happened</description></item>
        /// </list>
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnItemCreated(object sender, DataGridItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Header)
            {
                ExpiredFundAllocations fundAllocations = FundAllocationsInstance;
                Label sortSymbol = new Label();
                sortSymbol.Text = fundAllocations.SortAscending ? InsightUtilities.Constants.SortAscendingText : InsightUtilities.Constants.SortDescendingText;
                sortSymbol.Font.Name = InsightUtilities.Constants.SortSymbolFontName;

                Hashtable columnMap = new Hashtable();
                foreach (DataGridColumn column in expiredFundGrid.Columns)
                {
                    columnMap[column.SortExpression] = expiredFundGrid.Columns.IndexOf(column);
                }

                string sortColumn = fundAllocations.SortColumn;
                if (columnMap.ContainsKey(sortColumn))
                {
                    (e.Item.Cells[(int) columnMap[sortColumn]]).Controls.Add(sortSymbol);
                }
            }
        }

        /// <summary>
        /// Handler for the event raised when a column header within the data grid is clicked.
        /// Set the currentpageindex to 0 as sorting need to be done on all records and not only on what is visible
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnSort(object sender, DataGridSortCommandEventArgs e)
        {
            if (e.SortExpression != string.Empty)
            {
                FundAllocationsInstance.Sort(e.SortExpression);
                CurrentPageIndex = 0;
                LoadDataGrid();
            }
        }

        /// <summary>
        /// Handler for the event raised when a row in the datagrid is databound.
        ///	Attach the feed status indicator to the salary allocated amount
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnItemDataBound(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
                {
                    FundAllocation fundAllocation = (FundAllocation) e.Item.DataItem;
                    if (fundAllocation.FeedSourceIndicator)
                    {
                        e.Item.Cells[(int) DataGridColumns.SalaryAllocated].Text =
                            fundAllocation.SalaryAllocated.ToString("c") + FeedIndicatorSymbol;
                    }
                }
            }
            catch (Exception ex)
            {
                Utility.ExceptionReport.WriteToEventLog("Expired Fund", ex,
                    true, Utility.ExceptionReport.ReportType.Error);
                annunciator.Message = "Error while attempting to format columns.";
            }
        }

        #endregion

        #region Paging event handlers

        /// <summary>
        /// Handler for the event raised when the FirstPage link is clicked in the Pager control.
        /// Set the current page index to 0, bind the datagrid with data and manage navigation links.
        /// To avoid superfluous data binding activites, no action is taken if the current page index is already 0.
        /// </summary>
        /// <param name="sender">Control which rasied the event</param>
        /// <param name="e">Arguments associated with the event</param>
        protected void OnFirstPage(object sender, CommandEventArgs e)
        {
            CurrentPageIndex = 0;
            LoadDataGrid();
        }

        /// <summary>
        /// Handler for the event raised when the LastPage link is clicked in the Pager control.
        /// Set the current page index to one less than the total page count (index is 0-based), bind the datagrid with
        /// data and manage navigation links.
        /// To avoid superfluous data binding activites, no action is taken if the current 
        /// page index is already corresponding to the last page.
        /// </summary>
        /// <param name="sender">Control which rasied the event</param>
        /// <param name="e">Arguments associated with the event</param>
        protected void OnLastPage(object sender, CommandEventArgs e)
        {
            CurrentPageIndex = pagerAboveDatagrid.PageCount - 1;
            LoadDataGrid();
        }

        /// <summary>
        /// Handler for the event raised when the NextPage link is clicked in the Pager control.
        /// Increment the current page index, bind the datagrid with data and manage navigation links.
        /// </summary>
        /// <param name="sender">Control which rasied the event</param>
        /// <param name="e">Arguments associated with the event</param>
        protected void OnNextPage(object sender, CommandEventArgs e)
        {
            ++CurrentPageIndex;
            LoadDataGrid();
        }

        /// <summary>
        /// Handler for the event raised when the PreviousPage link is clicked in the Pager control.
        /// Decrement the current page index, bind the datagrid with data and manage navigation links.
        /// </summary>
        /// <param name="sender">Control which rasied the event</param>
        /// <param name="e">Arguments associated with the event</param>
        protected void OnPreviousPage(object sender, CommandEventArgs e)
        {
            --CurrentPageIndex;
            LoadDataGrid();
        }

        #endregion

        #region Search event handler

        /// <summary>
        /// Handler for the event raised when the Search button is clicked in the Search control.
        /// Gets the search criteia and performs a search. The actual search is performed by the ExpiredFundAllocations object
        /// which returns true if it did indeed apply any filteration criteria, and false otherwise. This predicate
        /// is used by LoadDataGrid() to control the visibility of the pager controls.
        /// </summary>
        /// <param name="args">Search Criteria args associated with the search event</param>
        protected void OnSearch(SearchCriteriaArgs args)
        {
            ProcessSearch();
        }

        /// <summary>
        /// Handler for the event raised when the "Clear Selection" button is clicked on the page.
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnClearSelection(object sender, CommandEventArgs e)
        {
            expiredFundGrid.Visible = false;
            pagerAboveDatagrid.Visible = pagerBelowDatagrid.Visible = false;
        }

        #endregion

        #region Downloadbar event handlers

        /// <summary>
        /// Invoked by the download bar when it catches an exception.
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnDownloadFailed(object sender, CommandEventArgs e)
        {
            annunciator.Title = "Following error(s) occurred while downloading";
            annunciator.Message = Utility.ExceptionReport.GetExceptionInfo((Exception) e.CommandArgument, false);
        }

        #endregion

        #region Header

        /// <summary>
        /// Resets the subnavigation selected link(s) before the 
        /// header performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnHeaderNavigate(object sender, CommandEventArgs e)
        {
            personnelSubNavigation.Reset();
            PurgeCache();
        }

        #endregion

        #endregion

        #region Private Methods

        /// <summary>
        /// Load the datagrid with sufficient data for display within one page of the data grid. This is done as follows:
        /// Get the fund allocations that the user has access to. Use that to initialize the data grid and
        /// the pager controls based on the page size of the data grid.
        /// The pagers are made visible only when more than one page of data can be displayed.
        /// If there is no data to display, warn the user via the annunciator.
        /// </summary>
        private void LoadDataGrid()
        {
            try
            {
                ExpiredFundAllocations fundAllocations = FundAllocationsInstance;
                expiredFundGrid.VirtualItemCount = pagerAboveDatagrid.RecordCount
                    = pagerBelowDatagrid.RecordCount = fundAllocations.Count;

                int currentPageIndex = CurrentPageIndex;
                int pageCount = (pagerAboveDatagrid.RecordCount/expiredFundGrid.PageSize) +
                    (((pagerAboveDatagrid.RecordCount%expiredFundGrid.PageSize) == 0) ? 0 : 1);
                pagerBelowDatagrid.PageCount = pagerAboveDatagrid.PageCount = pageCount;
                pagerBelowDatagrid.CurrentPage = pagerAboveDatagrid.CurrentPage = currentPageIndex + 1;

                expiredFundGrid.DataSource = fundAllocations.GetAllocationList
                    (currentPageIndex*expiredFundGrid.PageSize, expiredFundGrid.PageSize);
                expiredFundGrid.DataBind();

                expiredFundGrid.Visible = pagerBelowDatagrid.Visible = pagerAboveDatagrid.Visible =
                    (expiredFundGrid.Items.Count > 0);
                if (pagerAboveDatagrid.Visible)
                {
                    ManagePagination();
                }
                else
                {
                    annunciator.Message = "No expired fund allocation data found for user";
                }
            }
            catch (Exception ex)
            {
                expiredFundGrid.Visible = pagerBelowDatagrid.Visible = pagerAboveDatagrid.Visible = false;
                annunciator.Message = Utility.ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// Manages the pagination logic.
        /// Set the First record and last record values for the pager controls
        /// based on the current page index and the data grid page size respectively
        /// </summary>
        private void ManagePagination()
        {
            int currentPageIndex = CurrentPageIndex;
            expiredFundGrid.CurrentPageIndex = currentPageIndex;

            int startIndex = currentPageIndex*expiredFundGrid.PageSize;

            pagerBelowDatagrid.FirstRecord = pagerAboveDatagrid.FirstRecord = startIndex + 1;
            pagerBelowDatagrid.LastRecord = pagerAboveDatagrid.LastRecord =
                Math.Min(startIndex + expiredFundGrid.PageSize, expiredFundGrid.VirtualItemCount);

            pagerBelowDatagrid.EnableFirstPage = pagerAboveDatagrid.EnableFirstPage =
                pagerBelowDatagrid.EnablePreviousPage = pagerAboveDatagrid.EnablePreviousPage =
                    (CurrentPageIndex != 0);

            pagerBelowDatagrid.EnableLastPage = pagerAboveDatagrid.EnableLastPage =
                pagerBelowDatagrid.EnableNextPage = pagerAboveDatagrid.EnableNextPage =
                    (CurrentPageIndex != (pagerAboveDatagrid.PageCount - 1));
        }


        /// <summary>
        /// Adds refresh dates currently visible on the page to the search criteria string
        /// to be passed down to reports. The criteria does not persist to the SearchCriteria
        /// object.
        /// </summary>
        /// <param name="searchCriteria">Object containing search criteria.</param>
        /// <returns>A string representation of search criteria. </returns>
        private string AddRefreshDatesToCriteria(SearchCriteria searchCriteria)
        {
            StringBuilder criteria = new StringBuilder(searchCriteria.ToString(";"));
            if (refreshDates.SalaryAsOfDateVisible)
            {
                criteria.AppendFormat("Last Salary Post|{0};", refreshDates.SalaryAsOfDate.ToShortDateString());
            }
            if (refreshDates.GLAsOfDateVisible)
            {
                criteria.AppendFormat("Last GL Post|{0};", refreshDates.GLPostAsOfDate.ToShortDateString());
            }
            if (refreshDates.POAPAsOfDateVisible)
            {
                criteria.AppendFormat("Last PO/AP Post|{0};", refreshDates.POAPAsOfDate.ToShortDateString());
            }
            return criteria.ToString();
        }

        /// <summary>
        /// Search the summary data for the specified search criteria
        /// </summary>
        private void ProcessSearch()
        {
            try
            {
                CommonSearchContext searchContext = (CommonSearchContext) cachePolicy.GetCachedObject(CommonSearchContext.CacheKey);
                SearchCriteria searchCriteria = searchContext.GetSearchCriteria(Page.Request.Url.ToString());

                hiddenSearchCriteria.Value = HttpUtility.UrlEncode(AddRefreshDatesToCriteria(searchCriteria));
                FundAllocationsInstance.Search
                    (searchCriteria);
            }
            catch (Exception ex)
            {
                annunciator.Message = Utility.ExceptionReport.GetExceptionInfo(ex, false);
            }
            CurrentPageIndex = 0;
            LoadDataGrid();
            ManagePagination();
        }

        #endregion

        #region Web Form Designer generated code

        /// <summary>
        /// Handler for the event raised when the page is being initialized.
        /// Retrieve the cache policy and page cache policy in force.
        /// Deposit event handlers to support the datagrid pagination.
        /// </summary>
        /// <param name="e">Argument associated with the event</param>
        protected override void OnInit(EventArgs e)
        {
            cachePolicy = (Policy.ICachePolicy) Session[Policy.Names.CachePolicyKey];
            pageCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.PageCachePolicyKey];

            InitializeComponent();
            base.OnInit(e);
        }

        /// <summary>
        /// Required method for Designer support
        /// </summary>
        private void InitializeComponent()
        {
        }

        #endregion

        protected void OnSubHeaderNavigate(object sender, CommandEventArgs e)
        {
            PurgeCache();
        }

        protected void OnBreadCrumbNavigate(object sender, CommandEventArgs e)
        {
            PurgeCache();
        }

        public void PurgeCache()
        {
            cachePolicy.UnCache(ExpiredFundAllocations.CacheKey);
            ResultsCache.PurgeObject(cachePolicy);
        }
    }
}